package com.tanqing.ddd.web.bean;

import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class PageDto<T> implements Iterable<T>, Serializable {
    private int number;
    private int size;
    private long total;
    private boolean lastPage = false;
    private int totalPages;
    private List<T> content;

    public PageDto() {
    }

    public PageDto(final int number, final int size) {
        if (number > 0 && size > 0) {
            this.number = number;
            this.size = size;
            this.content = Collections.emptyList();
        } else {
            throw new IllegalArgumentException("number and size must gt 0!");
        }
    }

    public static <T> PageBuilder<T> pageBuilder(final int number, final int size) {
        return new PageBuilder(number, size);
    }

    public static <T> PageBuilder<T> pageBuilder(final Pageable pageable) {
        return new PageBuilder(pageable.getNumber(), pageable.getSize());
    }

    public int getOffset() {
        return (this.number - 1) * this.size;
    }

    public int getTotalPages() {
        return (int) ((this.total + (long) this.size - 1L) / (long) this.size);
    }

    public boolean hasNextPage() {
        return this.number < this.getTotalPages();
    }

    public boolean isLastPage() {
        return !this.hasNextPage();
    }

    public boolean hasPreviousPage() {
        return this.getNumber() > 1;
    }

    public boolean isFirstPage() {
        return !this.hasPreviousPage();
    }

    public boolean isEmpty() {
        return this.content.isEmpty();
    }

    public List<T> getContent() {
        return Collections.unmodifiableList(this.content);
    }

    public void setContent(final List<T> concent) {
        if (concent == null) {
            this.content = Collections.emptyList();
        }

        this.content = concent;
    }

    public Iterator<T> iterator() {
        return this.content.iterator();
    }

    public <R> PageDto<R> transform(final Function<T, R> function) {
        PageDto<R> page = new PageDto(this.number, this.size);
        page.setTotal(this.total);
        page.setContent((List) this.content.stream().map(function).collect(Collectors.toList()));
        return page;
    }

    public int getNumber() {
        return this.number;
    }

    public int getSize() {
        return this.size;
    }

    public long getTotal() {
        return this.total;
    }

    public void setNumber(final int number) {
        this.number = number;
    }

    public void setSize(final int size) {
        this.size = size;
    }

    public void setTotal(final long total) {
        this.total = total;
    }

    public void setLastPage(final boolean lastPage) {
        this.lastPage = lastPage;
    }

    public void setTotalPages(final int totalPages) {
        this.totalPages = totalPages;
    }

    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof PageDto)) {
            return false;
        } else {
            PageDto<?> other = (PageDto) o;
            if (!other.canEqual(this)) {
                return false;
            } else if (this.getNumber() != other.getNumber()) {
                return false;
            } else if (this.getSize() != other.getSize()) {
                return false;
            } else if (this.getTotal() != other.getTotal()) {
                return false;
            } else if (this.isLastPage() != other.isLastPage()) {
                return false;
            } else if (this.getTotalPages() != other.getTotalPages()) {
                return false;
            } else {
                Object this$content = this.getContent();
                Object other$content = other.getContent();
                if (this$content == null) {
                    if (other$content != null) {
                        return false;
                    }
                } else if (!this$content.equals(other$content)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(final Object other) {
        return other instanceof PageDto;
    }

    public int hashCode() {
        int result = 1;
        result = result * 59 + this.getNumber();
        result = result * 59 + this.getSize();
        long $total = this.getTotal();
        result = result * 59 + (int) ($total >>> 32 ^ $total);
        result = result * 59 + (this.isLastPage() ? 79 : 97);
        result = result * 59 + this.getTotalPages();
        Object $content = this.getContent();
        result = result * 59 + ($content == null ? 43 : $content.hashCode());
        return result;
    }

    public String toString() {
        return "PageDto(number=" + this.getNumber() + ", size=" + this.getSize() + ", total=" + this.getTotal() + ", lastPage=" + this.isLastPage() + ", totalPages=" + this.getTotalPages() + ", content=" + this.getContent() + ")";
    }

    public static class PageBuilder<T> {
        private final PageDto<T> page;

        public PageBuilder(int number, int size) {
            this.page = new PageDto(number, size);
        }

        public PageBuilder<T> total(final long total) {
            this.page.setTotal(total);
            int mode = (int) (total % (long) this.page.getSize());
            int pageSize;
            if (mode == 0) {
                pageSize = (int) (total / (long) this.page.getSize());
            } else {
                pageSize = (int) (total / (long) this.page.getSize()) + 1;
            }

            this.page.setTotalPages(pageSize);
            if (this.page.getNumber() >= pageSize) {
                this.page.setLastPage(true);
            }

            return this;
        }

        public PageBuilder<T> content(final List<T> content) {
            this.page.setContent(content);
            return this;
        }

        public PageDto<T> build() {
            return this.page;
        }
    }
}
